﻿
namespace StyleCopMaker.StyleCopMaker.Cleanup
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using EnvDTE;

    public class CSharpCleanupCode : ICleanupCode
    {
        public StyleCopMakerPackage Package { get; set; }

        public string DocumentType
        {
            get { return "CSharp"; }
        }

        public void InitCleaner()
        {
            if (System.Security.Principal.WindowsIdentity.GetCurrent() != null)
            {
                userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;

                if (userName.Contains("\\"))
                {
                    userName = userName.Substring(userName.IndexOf("\\") + 1);
                }
            }
        }

        public void Clean(EnvDTE.Document document)
        {
            TextDocument textDocument = (TextDocument)document.Object("TextDocument");
            StyleCopSettings settings = StyleCopSettings.GetSettings(document.FullName);

            RunVSFormatting();

            RemoveUnusedUsing();
            AddUsing(textDocument);
            SortUsing();
            // Move Using to Namespace

            RemoveBlankLines(textDocument);
            RemoveBlankLinesAfterOpenBrace(textDocument);
            RemoveBlankLinesBeforCloseBrace(textDocument);
            InsertBlankLinesAfterCloseBrace(textDocument);

            // Write Header
            AddStyleCopHeaderFile(settings, textDocument, document);
            // Add space at begin Comment
        }

        private string userName;

        private void AddStyleCopHeaderFile(StyleCopSettings settings, TextDocument textDocument, Document document)
        {
            if (settings == null)
            {
                return;
            }

            EditPoint point = textDocument.StartPoint.CreateEditPoint();
            if (!point.FindPattern("^//", (int)vsFindOptions.vsFindOptionsRegularExpression))
            {
                point.StartOfLine();
                point.Insert(String.Format("// <copyright file=\"{0}\" company=\"{1}\"> \n", document.Name, settings.CompanyName));
                point.Insert(String.Format("//     {0}\n", settings.Copyright));
                point.Insert("// </copyright> \n");
                point.Insert(String.Format("// <author>{0}</author> \n", userName));
                point.Insert("\n");
            }
        }

        private void InsertBlankLinesAfterCloseBrace(TextDocument textDocument)
        {
            textDocument.ReplacePattern(@"\}\n{:b+[^\}:b]}", @"}\n\n\1", (int)vsFindOptions.vsFindOptionsRegularExpression);
            textDocument.ReplacePattern(@"\}\n\n+{:b+(else|catch|finally|set)}", @"}\n\1", (int)vsFindOptions.vsFindOptionsRegularExpression);
        }

        private void RemoveBlankLinesAfterOpenBrace(TextDocument textDocument)
        {
            textDocument.ReplacePattern(@"\{\n\n+{:b+[^\}:b\n]}", @"{\n\1", (int)vsFindOptions.vsFindOptionsRegularExpression);
        }

        private void RemoveBlankLinesBeforCloseBrace(TextDocument textDocument)
        {
            textDocument.ReplacePattern(@"{[^\{]}\n\n+{:b+}\}", @"\1\n\2}", (int)vsFindOptions.vsFindOptionsRegularExpression);
        }

        /// <summary>
        /// Supprime les lignes blanches consécutives
        /// </summary>
        /// <param name="textDocument"></param>
        private void RemoveBlankLines(TextDocument textDocument)
        {
            textDocument.ReplacePattern(@"\n\n\n+{[^\n]}", @"\n\n\1", (int)vsFindOptions.vsFindOptionsRegularExpression);
        }

        /// <summary>
        /// Ajout les usings par defaut
        /// </summary>
        /// <param name="textDocument"></param>
        private void AddUsing(TextDocument textDocument)
        {
            List<string> usingList = new List<string>();
            usingList.Add("System");
            usingList.Add("System.Collections.Generic");
            usingList.Add("System.Linq");

            EditPoint point = null;
            textDocument.StartPoint.CreateEditPoint().FindPattern("using ", EndPoint: ref point);

            if (point == null)
            {
                textDocument.StartPoint.CreateEditPoint().FindPattern("</author>", EndPoint: ref point);
                if (point != null)
                {
                    point.LineDown();
                }
                else
                {
                    point = textDocument.StartPoint.CreateEditPoint();
                }
            }

            point.StartOfLine();

            foreach (var item in usingList)
            {
                string usingText = "using " + item + ";\n";

                if (!textDocument.StartPoint.CreateEditPoint().FindPattern(usingText))
                {
                    point.Insert(usingText);
                }
            }
        }

        /// <summary>
        /// Supprime les using non utilisé
        /// </summary>
        private void RemoveUnusedUsing()
        {
            // Requires VS2008 (version 9).
            if (Package.IDEVersion >= 9)
            {
                Package.IDE.ExecuteCommand("Edit.RemoveUnusedUsings", String.Empty);
            }
        }

        /// <summary>
        /// Tris les usings
        /// </summary>
        private void SortUsing()
        {
            // Requires VS2008 (version 9).
            if (Package.IDEVersion >= 9)
            {
                Package.IDE.ExecuteCommand("Edit.SortUsings", String.Empty);
            }
        }

        /// <summary>
        /// VS Format (Indentation, ...)
        /// </summary>
        private void RunVSFormatting()
        {
            Package.IDE.ExecuteCommand("Edit.FormatDocument", String.Empty);
        }
    }
}